snapshot: Add gtk_snapshot_push_blend()
authorBenjamin Otte <otte@redhat.com>
Thu, 12 Jan 2017 22:20:31 +0000 (23:20 +0100)
committerBenjamin Otte <otte@redhat.com>
Fri, 13 Jan 2017 02:38:36 +0000 (03:38 +0100)
and use it for backgrounds.

docs/reference/gtk/gtk4-sections.txt
gtk/gtkrenderbackground.c
gtk/gtksnapshot.c
gtk/gtksnapshot.h
gtk/gtksnapshotprivate.h

index 13a4b0d30bfcd6c0eb955efd344329318018cef1..76fb07966c4d096247b7f5dedd4e0de0f12ec1d7 100644 (file)
@@ -4459,6 +4459,7 @@ gtk_snapshot_push_repeat
 gtk_snapshot_push_clip
 gtk_snapshot_push_rounded_clip
 gtk_snapshot_push_cross_fade
+gtk_snapshot_push_blend
 gtk_snapshot_pop
 gtk_snapshot_pop_and_append
 gtk_snapshot_set_transform
index e52d1de3b7ffbdc7e10f0ee6b490340523e4357e..6d2f2fd95320e957fb428f0ad83ad836f35df2cc 100644 (file)
@@ -619,6 +619,8 @@ gtk_css_style_snapshot_background (GtkCssStyle      *style,
   gint idx;
   GtkCssValue *background_image;
   GtkCssValue *box_shadow;
+  GtkCssValue *blend_modes;
+  GskBlendMode blend_mode;
   const GdkRGBA *bg_color;
   gint number_of_layers;
 
@@ -639,71 +641,32 @@ gtk_css_style_snapshot_background (GtkCssStyle      *style,
                                          snapshot,
                                          &bg.boxes[GTK_CSS_AREA_BORDER_BOX]);
 
-  /*
-   * When we have a blend mode set for the background, we must blend on a transparent
-   * background. GSK can't do that yet.
-   */
-  if (_gtk_theming_background_needs_push_group (style))
-    {
-      GtkCssValue *blend_modes;
-      GskBlendMode blend_mode;
+  blend_modes = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_BLEND_MODE);
+  number_of_layers = _gtk_css_array_value_get_n_values (background_image);
 
-      blend_modes = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_BLEND_MODE);
+  for (idx = number_of_layers - 1; idx >= 0; idx--)
+    {
+      blend_mode = _gtk_css_blend_mode_value_get (_gtk_css_array_value_get_nth (blend_modes, idx));
 
-      gtk_snapshot_push (snapshot, TRUE, "BackgroundBlendGroup");
+      if (blend_mode != GSK_BLEND_MODE_DEFAULT)
+        gtk_snapshot_push_blend (snapshot, blend_mode, "Background<%u>Blend<%u>", idx, blend_mode);
+    }
 
-      gtk_theming_background_snapshot_color (&bg, snapshot, bg_color, background_image);
+  gtk_theming_background_snapshot_color (&bg, snapshot, bg_color, background_image);
 
-      number_of_layers = _gtk_css_array_value_get_n_values (background_image);
+  for (idx = number_of_layers - 1; idx >= 0; idx--)
+    {
+      blend_mode = _gtk_css_blend_mode_value_get (_gtk_css_array_value_get_nth (blend_modes, idx));
 
-      for (idx = number_of_layers - 1; idx >= 0; idx--)
+      if (blend_mode == GSK_BLEND_MODE_DEFAULT)
         {
-          blend_mode = _gtk_css_blend_mode_value_get (_gtk_css_array_value_get_nth (blend_modes, idx));
-
-          if (blend_mode == GSK_BLEND_MODE_DEFAULT)
-            {
-              gtk_theming_background_snapshot_layer (&bg, idx, snapshot);
-            }
-          else
-            {
-              GskRenderNode *bottom, *top, *blend;
-
-              bottom = gtk_snapshot_pop (snapshot);
-
-              gtk_snapshot_push (snapshot, TRUE, "BackgroundBlendGroup<Mode%u>", blend_mode);
-              gtk_theming_background_snapshot_layer (&bg, idx, snapshot);
-              top = gtk_snapshot_pop (snapshot);
-
-              /* XXX: Is this necessary? Do we need a NULL node? */
-              if (top == NULL)
-                top = gsk_container_node_new (NULL, 0);
-              if (bottom == NULL)
-                bottom = gsk_container_node_new (NULL, 0);
-
-              blend = gsk_blend_node_new (bottom, top, blend_mode);
-              if (snapshot->record_names)
-                gsk_render_node_set_name (blend, "BackgroundBlend");
-
-              gtk_snapshot_push (snapshot, TRUE, "BackgroundBlendGroup");
-              gtk_snapshot_append_node (snapshot, blend);
-
-              gsk_render_node_unref (blend);
-              gsk_render_node_unref (top);
-              gsk_render_node_unref (bottom);
-            }
+          gtk_theming_background_snapshot_layer (&bg, idx, snapshot);
         }
-
-      gtk_snapshot_pop_and_append (snapshot);
-    }
-  else
-    {
-      gtk_theming_background_snapshot_color (&bg, snapshot, bg_color, background_image);
-
-      number_of_layers = _gtk_css_array_value_get_n_values (background_image);
-
-      for (idx = number_of_layers - 1; idx >= 0; idx--)
+      else
         {
+          gtk_snapshot_pop_and_append (snapshot);
           gtk_theming_background_snapshot_layer (&bg, idx, snapshot);
+          gtk_snapshot_pop_and_append (snapshot);
         }
     }
 
index d79f9039c13e41428f5283518a4a82c8bfee84de..3e0b9f4e0ca9c8c41913968ed1db928ec506576b 100644 (file)
@@ -675,6 +675,97 @@ gtk_snapshot_push_shadow (GtkSnapshot            *snapshot,
   snapshot->state = state;
 }
 
+static GskRenderNode *
+gtk_snapshot_collect_blend_top (GtkSnapshotState *state,
+                                GskRenderNode   **nodes,
+                                guint             n_nodes,
+                                const char       *name)
+{
+  GskRenderNode *bottom_node, *top_node, *blend_node;
+
+  top_node = gtk_snapshot_collect_default (state, nodes, n_nodes, name);
+  bottom_node = state->data.blend.bottom_node;
+
+  /* XXX: Is this necessary? Do we need a NULL node? */
+  if (top_node == NULL)
+    top_node = gsk_container_node_new (NULL, 0);
+  if (bottom_node == NULL)
+    bottom_node = gsk_container_node_new (NULL, 0);
+
+  blend_node = gsk_blend_node_new (bottom_node, top_node, state->data.blend.blend_mode);
+  gsk_render_node_set_name (blend_node, name);
+
+  gsk_render_node_unref (top_node);
+  gsk_render_node_unref (bottom_node);
+
+  return blend_node;
+}
+
+static GskRenderNode *
+gtk_snapshot_collect_blend_bottom (GtkSnapshotState *state,
+                                   GskRenderNode   **nodes,
+                                   guint             n_nodes,
+                                   const char       *name)
+{
+  state->parent->data.blend.bottom_node = gtk_snapshot_collect_default (state, nodes, n_nodes, name);
+  
+  return NULL;
+}
+
+/**
+ * gtk_snapshot_push_blend:
+ * @snapshot: a #GtkSnapshot
+ * @blend_mode: blend mode to use
+ * @name: printf format string for name of the pushed node
+ * @...: printf-style arguments for the @name string
+ *
+ * Blends together 2 images with the given blend mode.
+ *
+ * Until the first call to gtk_snapshot_pop(), the bottom image for the
+ * blend operation will be recorded. After that call, the top image to
+ * be blended will be recorded until the second call to gtk_snapshot_pop().
+ *
+ * Calling this function requires 2 subsequent calls to gtk_snapshot_pop().
+ **/
+void
+gtk_snapshot_push_blend (GtkSnapshot  *snapshot,
+                         GskBlendMode  blend_mode,
+                         const char   *name,
+                         ...)
+{
+  GtkSnapshotState *state;
+  char *str;
+
+  if (name && snapshot->record_names)
+    {
+      va_list args;
+
+      va_start (args, name);
+      str = g_strdup_vprintf (name, args);
+      va_end (args);
+    }
+  else
+    str = NULL;
+
+  state = gtk_snapshot_state_new (snapshot->state,
+                                  str,
+                                  snapshot->state->clip_region,
+                                  snapshot->state->translate_x,
+                                  snapshot->state->translate_y,
+                                  gtk_snapshot_collect_blend_top);
+  state->data.blend.blend_mode = blend_mode;
+  state->data.blend.bottom_node = NULL;
+
+  state = gtk_snapshot_state_new (state,
+                                  str,
+                                  state->clip_region,
+                                  state->translate_x,
+                                  state->translate_y,
+                                  gtk_snapshot_collect_blend_bottom);
+
+  snapshot->state = state;
+}
+
 static GskRenderNode *
 gtk_snapshot_collect_cross_fade_end (GtkSnapshotState *state,
                                      GskRenderNode   **nodes,
index 7ac7a43481259defbc7c3ce501c429c9f497fb97..b59f32ce58de4ac7056ca47098c3d3bc556ae8cc 100644 (file)
@@ -80,6 +80,11 @@ void            gtk_snapshot_push_shadow                (GtkSnapshot
                                                          const char             *name,
                                                          ...) G_GNUC_PRINTF (4, 5);
 GDK_AVAILABLE_IN_3_90
+void            gtk_snapshot_push_blend                 (GtkSnapshot            *snapshot,
+                                                         GskBlendMode            blend_mode,
+                                                         const char             *name,
+                                                         ...) G_GNUC_PRINTF (3, 4);
+GDK_AVAILABLE_IN_3_90
 void            gtk_snapshot_push_cross_fade            (GtkSnapshot            *snapshot,
                                                          double                  progress,
                                                          const char             *name,
index 3989bc5fde7dee1a56fc7440fdd2f24e0a939999..3676a10859f7fa949a0881004c7cbabdaf46eb9c 100644 (file)
@@ -67,6 +67,10 @@ struct _GtkSnapshotState {
       GskShadow *shadows;
       GskShadow a_shadow; /* Used if n_shadows == 1 */
     } shadow;
+    struct {
+      GskBlendMode blend_mode;
+      GskRenderNode *bottom_node;
+    } blend;
     struct {
       double progress;
       GskRenderNode *start_node;